#include "StdAfx.h"
#include "ChunkSceneManager.h"

#include "TerrainBlockChunkItem.h"
#include "SpecifiedChunk.h"
#include "ChunkModel.h"

using namespace ChunkSystem;
using namespace Common;

const char*	m_pChunkItemStr[] = 
{
	"model",
	"speedtree",
	"particles",
	"navmesh",
	"terrain",
	"entity",
	"chunk"
};

ChunkSceneManager::ChunkSceneManager(void)
{
	//::memset( m_pChunkItemFactories, 0, eEnd * 4 );

	//register all factory
	ChunkItemFactory* pFactory = NULL;
	pFactory = new TerrainBlockChunkFactory();
	this->RegisterMovableFactory( pFactory );

	pFactory = new InternalChunkFactory();
	this->RegisterMovableFactory( pFactory );
	
	pFactory = new ChunkModelFactory();
	this->RegisterMovableFactory( pFactory );
}

ChunkSceneManager::~ChunkSceneManager(void)
{
}

TiXmlElement* ChunkSceneManager::GetChunkRoot( const String& strChunkFilePath , bool bCreate )
{
	size_t i = strChunkFilePath.rfind("/");
	if( i == -1 )
	{
		i = strChunkFilePath.rfind("\\");
		if( i == -1 )
		{
			assert( !"path format is invalid." );
			return NULL;
		}
	}

	size_t iDot = strChunkFilePath.rfind(".");
	if( iDot == -1 )
	{
		assert( !"path format is invalid." );
		return NULL;
	}

	String strChunkId = strChunkFilePath.substr( i + 1 , iDot - i - 1);
	ItrMapChunkNodes ptrChunk = m_ChunkDocNodes.find( strChunkId );
	if( ptrChunk != m_ChunkDocNodes.end()  )
	{
		if( ptrChunk->second.FirstChild().ToElement() == NULL )
			return NULL;
		return ptrChunk->second.FirstChild().ToElement();
	}

	TiXmlDocument* pDoc = new TiXmlDocument( strChunkFilePath );
	TiXmlHandle docHandle( pDoc );
	String strId = "";

	if( !pDoc->LoadFile() )
	{
		if( bCreate )
		{
			TiXmlNode* pRoot = pDoc->InsertEndChild( TiXmlElement("chunk") );
			pRoot->ToElement()->SetAttribute( "id",strChunkId );
		}
		else
			return NULL;
	}
	else
	{

		TiXmlHandle ptrRoot = docHandle.FirstChildElement();
		if( ptrRoot.ToElement() == NULL )
			return NULL;

		strId = ptrRoot.ToElement()->Attribute("id");
		if( strId.empty() )
		{
			assert(!("incorrect format"));
			return NULL;
		}
	}
	//m_ChunkDocNodes.insert( MapChunkNodes::value_type(strId, docHandle) );

	return docHandle.FirstChild().ToElement();
}

String ChunkSceneManager::GetTag( ChunkItemType eType )
{
	assert( eType < eEnd );
	return m_pChunkItemStr[eType];
}

bool ChunkSceneManager::CreateChunkItemByType( Chunk* pOwnerChunk, TiXmlElement* pChunkRoot, ChunkItemType eChunkType )
{
	assert( eChunkType < eEnd );

	bool bRet = true;
	TiXmlHandle rootHandle(pChunkRoot);
	for( int i = 0 ; ; i++)
	{
		TiXmlElement* pChunkItemData = rootHandle.ChildElement( m_pChunkItemStr[eChunkType] , i ).ToElement();
		if( pChunkItemData == NULL )
			break;

		ChunkItemFactory::ChunkCreateContext objChunkItemContext;
		objChunkItemContext.pOwner = pOwnerChunk;
		objChunkItemContext.pChunkItemData = pChunkItemData;

		std::auto_ptr<ChunkItem> ptrNewChunkItem ( static_cast<ChunkItem*>( this->CreateMovable( m_pChunkItemStr[eChunkType], &objChunkItemContext ) ) );
		if( ptrNewChunkItem.get() == NULL )
			continue;

		//if the chunkitem is an internal chunk we should put it into chunk loading queue again.
		if( ptrNewChunkItem->Load( pChunkItemData ) )
			pOwnerChunk->AddChunkItem(ptrNewChunkItem.release());
		else
		{
			assert( !("faild to load chunk item") );
			bRet = false;
		}
	}

	return bRet;
}
